Purchase Flows
Begin only after you have successfully requested a quote and stored the returned quoteId (and optionally premiumSummary.quoteLinkUrl).
Overview
Two primary ways to complete a purchase after quoting:
- Quote Engine Redirect – Use the
quoteLinkUrlto send the user to the hosted Embrace Quote Engine experience where they can finalize purchase. - Stripe Embedded Checkout – Stay on your site, collect payment using Stripe Elements, then call the Embrace Stripe purchase endpoint.
Choose based on UX preference and integration depth. Both start from the same quote response.
Redirect (Quote Engine) Flow
1. Obtain quoteLinkUrl
Already covered in the quote request guide: ensure you capture premiumSummary.quoteLinkUrl from the quote response.
2. (Optional) Add Pets Incrementally
If a pet was omitted initially, you may add it using: POST /v2/quotes/fullquote/{quoteId}/pet. See Add a Pet.
3. Redirect User
Redirect the browser to the quoteLinkUrl when the customer chooses to continue. Use a normal window.location.href = quoteLinkUrl; navigation. Consider preserving UTM analytics separately if needed.
Stripe Purchase Flow
The embedded flow keeps the customer on your site while you orchestrate payment collection via Stripe.
1. Checkout Request
Call the Embrace Checkout endpoint to retrieve Stripe keys needed to render a payment form.
Endpoint reference: Checkout Endpoint
Front-End (checkout request)
let publishableKey;
let clientSecret;
async function startCheckout(quoteId){
const resp = await fetch('/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ quoteId })
});
const data = await resp.json();
if(data.stripePublishableKey && data.stripeSetupIntentClientSecret){
publishableKey = data.stripePublishableKey;
clientSecret = data.stripeSetupIntentClientSecret;
} else {
throw new Error('Checkout response missing Stripe keys');
}
}
Backend Example
app.MapPost("/checkout", async (HttpRequest request) =>
{
using var reader = new StreamReader(request.Body, Encoding.UTF8);
var rawBody = await reader.ReadToEndAsync();
if (string.IsNullOrWhiteSpace(rawBody)) return Results.BadRequest(new { error = "Request body is empty" });
string? quoteId = null;
try
{
using var doc = JsonDocument.Parse(rawBody);
if (doc.RootElement.TryGetProperty("quoteId", out var q)) quoteId = q.GetString();
}
catch { }
if (string.IsNullOrWhiteSpace(quoteId)) return Results.BadRequest(new { error = "quoteId field is required" });
var upstream = new HttpRequestMessage(HttpMethod.Post, $"https://[embrace-test-endpoint]/v2/quotes/{quoteId}/checkout")
{
Content = new StringContent(rawBody, Encoding.UTF8, "application/json")
};
upstream.Headers.Add("epi-apim-subscription-key", embraceApiKey);
var upstreamResp = await httpClient.SendAsync(upstream);
var body = await upstreamResp.Content.ReadAsStringAsync();
return Results.Content(body, "application/json", upstreamResp.StatusCode);
});
2. Initialize Stripe Elements
Use the publishable key + client secret to render the payment form.
let stripe, elements, paymentMethodId;
function initStripe(){
stripe = Stripe(publishableKey);
const appearance = { theme: 'stripe' };
elements = stripe.elements({ appearance, clientSecret });
const paymentElement = elements.create('payment', { layout: 'tabs' });
paymentElement.mount('#payment-element');
}
3. Confirm Setup (Obtain Payment Method Token)
async function confirmPaymentMethod(){
const { setupIntent, error } = await stripe.confirmSetup({
elements,
confirmParams: {},
redirect: 'if_required'
});
if(error){
console.error(error);
throw error;
}
paymentMethodId = setupIntent.payment_method;
return paymentMethodId;
}
4. Purchase (Stripe)
Call the Embrace Stripe purchase endpoint providing the payment method token and quote reference.
Endpoint reference: Purchase (Stripe) Endpoint
Front-End
async function completePurchase(){
const body = {
paymentMethodToken: paymentMethodId,
quoteIdToPurchase: quoteId,
analytics,
allPetsVisitedVet,
mailingAddress,
billingAddress,
agreeToTermsOfService,
firstName,
lastName
};
const resp = await fetch('/purchase-stripe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const data = await resp.json();
if(data.purchaseSucceeded){
console.log('Policy Number:', data.policyNumber);
} else {
console.error('Purchase error', data);
}
}
Backend Example
app.MapPost("/purchase-stripe", async (HttpRequest request) =>
{
using var reader = new StreamReader(request.Body, Encoding.UTF8);
var rawBody = await reader.ReadToEndAsync();
if (string.IsNullOrWhiteSpace(rawBody)) return Results.BadRequest(new { error = "Request body is empty" });
string? quoteId = null;
try
{
using var doc = JsonDocument.Parse(rawBody);
if (doc.RootElement.TryGetProperty("quoteIdToPurchase", out var q)) quoteId = q.GetString();
}
catch { }
if (string.IsNullOrWhiteSpace(quoteId)) return Results.BadRequest(new { error = "quoteIdToPurchase field is required" });
var upstream = new HttpRequestMessage(HttpMethod.Post, $"https://[embrace-test-endpoint]/v2/quotes/fullquote/{quoteId}/purchase-stripe")
{
Content = new StringContent(rawBody, Encoding.UTF8, "application/json")
};
upstream.Headers.Add("epi-apim-subscription-key", embraceApiKey);
var upstreamResp = await httpClient.SendAsync(upstream);
var body = await upstreamResp.Content.ReadAsStringAsync();
return Results.Content(body, "application/json", upstreamResp.StatusCode);
});
5. Success Handling
Successful purchase responses include policy identifiers:
{
"purchaseSucceeded": true,
"policyNumber": "INS-987654321"
}
Persist policyNumber and transition the user to a confirmation screen (avoid re-submission on refresh by clearing transient state).
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.